{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Deep Learning Models -- A collection of various deep learning architectures, models, and tips for TensorFlow and PyTorch in Jupyter Notebooks.\n",
    "- Author: Sebastian Raschka\n",
    "- GitHub Repository: https://github.com/rasbt/deeplearning-models"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sebastian Raschka \n",
      "\n",
      "CPython 3.7.3\n",
      "IPython 7.9.0\n",
      "\n",
      "torch 1.3.0\n"
     ]
    }
   ],
   "source": [
    "%load_ext watermark\n",
    "%watermark -a 'Sebastian Raschka' -v -p torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Runs on CPU or GPU (if available)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Autoencoder (MNIST) + Scikit-Learn Random Forest Classifier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A simple, single-hidden-layer, fully-connected autoencoder that compresses 768-pixel MNIST images into 32-pixel vectors (32-times smaller representations). A random forest classifier is then trained for predicting the class labels based on that 32-pixel compressed space."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Device: cuda:0\n",
      "Image batch dimensions: torch.Size([256, 1, 28, 28])\n",
      "Image label dimensions: torch.Size([256])\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn.functional as F\n",
    "from torchvision import datasets\n",
    "from torchvision import transforms\n",
    "from torch.utils.data import DataLoader\n",
    "\n",
    "if torch.cuda.is_available():\n",
    "    torch.backends.cudnn.deterministic = True\n",
    "\n",
    "\n",
    "##########################\n",
    "### SETTINGS\n",
    "##########################\n",
    "\n",
    "# Device\n",
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "print('Device:', device)\n",
    "\n",
    "# Hyperparameters\n",
    "random_seed = 123\n",
    "learning_rate = 0.005\n",
    "num_epochs = 5\n",
    "batch_size = 256\n",
    "\n",
    "# Architecture\n",
    "num_features = 784\n",
    "num_hidden_1 = 32\n",
    "\n",
    "\n",
    "##########################\n",
    "### MNIST DATASET\n",
    "##########################\n",
    "\n",
    "# Note transforms.ToTensor() scales input images\n",
    "# to 0-1 range\n",
    "train_dataset = datasets.MNIST(root='data', \n",
    "                               train=True, \n",
    "                               transform=transforms.ToTensor(),\n",
    "                               download=True)\n",
    "\n",
    "test_dataset = datasets.MNIST(root='data', \n",
    "                              train=False, \n",
    "                              transform=transforms.ToTensor())\n",
    "\n",
    "\n",
    "train_loader = DataLoader(dataset=train_dataset, \n",
    "                          batch_size=batch_size, \n",
    "                          shuffle=True)\n",
    "\n",
    "test_loader = DataLoader(dataset=test_dataset, \n",
    "                         batch_size=batch_size, \n",
    "                         shuffle=False)\n",
    "\n",
    "# Checking the dataset\n",
    "for images, labels in train_loader:  \n",
    "    print('Image batch dimensions:', images.shape)\n",
    "    print('Image label dimensions:', labels.shape)\n",
    "    break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "##########################\n",
    "### MODEL\n",
    "##########################\n",
    "\n",
    "class Autoencoder(torch.nn.Module):\n",
    "\n",
    "    def __init__(self, num_features):\n",
    "        super(Autoencoder, self).__init__()\n",
    "        \n",
    "        ### ENCODER\n",
    "        \n",
    "        self.linear_1 = torch.nn.Linear(num_features, num_hidden_1)\n",
    "        # The following to lones are not necessary, \n",
    "        # but used here to demonstrate how to access the weights\n",
    "        # and use a different weight initialization.\n",
    "        # By default, PyTorch uses Xavier/Glorot initialization, which\n",
    "        # should usually be preferred.\n",
    "        self.linear_1.weight.detach().normal_(0.0, 0.1)\n",
    "        self.linear_1.bias.detach().zero_()\n",
    "        \n",
    "        ### DECODER\n",
    "        self.linear_2 = torch.nn.Linear(num_hidden_1, num_features)\n",
    "        self.linear_1.weight.detach().normal_(0.0, 0.1)\n",
    "        self.linear_1.bias.detach().zero_()\n",
    "        \n",
    "    def encoder(self, x):\n",
    "        encoded = self.linear_1(x)\n",
    "        encoded = F.leaky_relu(encoded)\n",
    "        return encoded\n",
    "    \n",
    "    def decoder(self, encoded_x):\n",
    "        logits = self.linear_2(encoded_x)\n",
    "        decoded = torch.sigmoid(logits)\n",
    "        return decoded\n",
    "        \n",
    "\n",
    "    def forward(self, x):\n",
    "        \n",
    "        ### ENCODER\n",
    "        encoded = self.encoder(x)\n",
    "        \n",
    "        ### DECODER\n",
    "        decoded = self.decoder(encoded)\n",
    "        \n",
    "        return decoded\n",
    "\n",
    "    \n",
    "torch.manual_seed(random_seed)\n",
    "model = Autoencoder(num_features=num_features)\n",
    "model = model.to(device)\n",
    "\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 001/005 | Batch 000/235 | Cost: 0.7100\n",
      "Epoch: 001/005 | Batch 050/235 | Cost: 0.2026\n",
      "Epoch: 001/005 | Batch 100/235 | Cost: 0.1635\n",
      "Epoch: 001/005 | Batch 150/235 | Cost: 0.1349\n",
      "Epoch: 001/005 | Batch 200/235 | Cost: 0.1301\n",
      "Time elapsed: 0.11 min\n",
      "Epoch: 002/005 | Batch 000/235 | Cost: 0.1238\n",
      "Epoch: 002/005 | Batch 050/235 | Cost: 0.1131\n",
      "Epoch: 002/005 | Batch 100/235 | Cost: 0.1099\n",
      "Epoch: 002/005 | Batch 150/235 | Cost: 0.1062\n",
      "Epoch: 002/005 | Batch 200/235 | Cost: 0.1035\n",
      "Time elapsed: 0.22 min\n",
      "Epoch: 003/005 | Batch 000/235 | Cost: 0.1009\n",
      "Epoch: 003/005 | Batch 050/235 | Cost: 0.0977\n",
      "Epoch: 003/005 | Batch 100/235 | Cost: 0.0983\n",
      "Epoch: 003/005 | Batch 150/235 | Cost: 0.0975\n",
      "Epoch: 003/005 | Batch 200/235 | Cost: 0.0937\n",
      "Time elapsed: 0.33 min\n",
      "Epoch: 004/005 | Batch 000/235 | Cost: 0.0946\n",
      "Epoch: 004/005 | Batch 050/235 | Cost: 0.0961\n",
      "Epoch: 004/005 | Batch 100/235 | Cost: 0.0960\n",
      "Epoch: 004/005 | Batch 150/235 | Cost: 0.0972\n",
      "Epoch: 004/005 | Batch 200/235 | Cost: 0.0899\n",
      "Time elapsed: 0.43 min\n",
      "Epoch: 005/005 | Batch 000/235 | Cost: 0.0948\n",
      "Epoch: 005/005 | Batch 050/235 | Cost: 0.0927\n",
      "Epoch: 005/005 | Batch 100/235 | Cost: 0.0932\n",
      "Epoch: 005/005 | Batch 150/235 | Cost: 0.0938\n",
      "Epoch: 005/005 | Batch 200/235 | Cost: 0.0935\n",
      "Time elapsed: 0.54 min\n",
      "Total Training Time: 0.54 min\n"
     ]
    }
   ],
   "source": [
    "start_time = time.time()\n",
    "for epoch in range(num_epochs):\n",
    "    for batch_idx, (features, targets) in enumerate(train_loader):\n",
    "        \n",
    "        # don't need labels, only the images (features)\n",
    "        features = features.view(-1, 28*28).to(device)\n",
    "            \n",
    "        ### FORWARD AND BACK PROP\n",
    "        decoded = model(features)\n",
    "        cost = F.binary_cross_entropy(decoded, features)\n",
    "        optimizer.zero_grad()\n",
    "        \n",
    "        cost.backward()\n",
    "        \n",
    "        ### UPDATE MODEL PARAMETERS\n",
    "        optimizer.step()\n",
    "        \n",
    "        ### LOGGING\n",
    "        if not batch_idx % 50:\n",
    "            print ('Epoch: %03d/%03d | Batch %03d/%03d | Cost: %.4f' \n",
    "                   %(epoch+1, num_epochs, batch_idx, \n",
    "                     len(train_loader), cost))\n",
    "            \n",
    "    print('Time elapsed: %.2f min' % ((time.time() - start_time)/60))\n",
    "    \n",
    "print('Total Training Time: %.2f min' % ((time.time() - start_time)/60))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Evaluation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Image batch dimensions: torch.Size([15, 1, 28, 28])\n",
      "Image label dimensions: torch.Size([15])\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABH0AAACqCAYAAAAwYjMwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nOyddaAkxfW2nw4JBBIcgsPimhBg4YcFAgSXxd1dwofDLu7uzmKBBPfFNVhCgF2cRRYITrAoEBIg/f2x+3bV9J0723PvSM/c9/ln5s709FSfW1VdU+c95yRpmmKMMcYYY4wxxhhjuovvtbsBxhhjjDHGGGOMMabxeNPHGGOMMcYYY4wxpgvxpo8xxhhjjDHGGGNMF+JNH2OMMcYYY4wxxpguxJs+xhhjjDHGGGOMMV2IN32MMcYYY4wxxhhjupB+bfokSbJakiSvJUnyRpIkQxvVKGOMMcYYY4wxxhjTP5I0Tfv2wSSZAHgdWBl4H3ga2CxN09GNa54xxhhjjDHGGGOM6Qv9UfosAbyRpulbaZr+F7gWGNKYZhljjDHGGGOMMcaY/vD9fnx2JuC96O/3gf+r9YFpppkmHTRoUD++sjMZNWrUZ2maTlvPZ2yr4thW9TEQ7fX222/z2WefJfV+biDaCjwO68G2Ko5tVRzP78Xx/F4fHofFsa2K4zmrOJ6z6sPjsDi1bNWfTZ9qnbVHrFiSJDsDOwPMOuusjBw5sh9f2ZkkSfJOweNsK9uqMEVtNe7YAW2vwYMHFz52oNsKPA7rwbYqjm1VHM/vxfH8Xh8eh8WxrYrjOas4nrPqw+OwOLVs1Z/wrveBWaK/ZwY+zB+UpunwNE0Hp2k6eNpp694AHlDYVsWxrerD9iqObVUc26o4tlVxbKv6sL2KY1sVx7Yqjm1VH7ZXcWyr4thWtenPps/TwNxJksyeJMmEwKbAiMY0yxhjjDHGGGOMMcb0hz6Hd6Vp+m2SJL8G7gUmAC5L0/TlhrXMGGOMMcYYY4wxxvSZ/uT0IU3Tu4C7GtQWY4wxxhhjjDHGGNMg+hPeZYwxxhhjjDHGGGNKSr+UPsYYY4wx3cQrr7wCwFVXXQXA8ccfD8D//ve/trXJGGOMMaavWOljjDHGGGOMMcYY04VY6WOMMcaYAcXw4cMBuOWWW7LXPvvsMwBeffVVAL788ksAkiQBYN99982OPfjggwGYZpppmt9Y0/W89tpr2fPll18egCOPPBKAXXfdtR1NMiXl22+/zZ5fcsklABx99NEA/OUvfwEgTVMA1l577exYKRYXWmihlrSzzHz++ecAHHbYYQC89NJLAGy//fbZMeuvvz4Ak002WYtbVy7OPvtsINwHL7roIgBGjx6dHXPmmWdWHDP55JMDsPXWW7esnWb8WOljjDHGGGOMMcYY04V0pNLn9NNPB+CYY44B4B//+Eevx2q3++c//zlQe9dxn332aVQT24q8QwCPPPIIAA8//PB4P/fLX/4SCF4m/a1H0zvffPMNELy/AKeeeioAG2+8MQDXXXdd6xtWcmJPgTwtstvTTz8NwG677QbA+eef3+LWNZ6///3vANxwww0A/Pa3v83ek8pgvvnmA4J3d5VVVmllE43pGj799NPs+S677ALArbfeCoS1gTyT1V7T3+KMM87InsuzqXvrcsst18immwGCVBvx/e3jjz8GYNlll21Lm8rCv/71LyAo7o466igALrzwwl4/I6XGGmusAcAGG2zQzCa2hfXWWy97ftddlQWUZ5ppJgA++OADAO68887svRdeeAEIa6qDDjqoqe0sI8rXttZaawHw1ltvVbz/2GOPZc+feOIJIChbuhn9VnznnXey14477jgAxowZA1TeK/N/77333hWvTTjhhBV/b7XVVs1otqkTK32MMcYYY4wxxhhjupCOVPrsv//+QNhBzO8+VkM73PpsNeTFU6z/aqut1q92tgp5GldYYYWGnEeP8qrESp8jjjiix2smeOlOO+207DX1S8UMm6BmOemkkwA477zzsve+/vprAKaffnoAppxySgBuuummis8ATDrppM1vbAORx/aLL74AwnwUM8ssswBBiaBxeNZZZwHws5/9bLzf86Mf/QiAueaaq38NbiPyQtbjXaum2sijfnXiiScC3RVr/p///AcIXrpRo0Zl78lbeeONNwLw0Ucf9fl7Zp555uz5KaecAsCmm27a5/M1Cyl85O2HYJNa3sreXqt1zH777QfA3XffDXRvjh/NzxqfEKqb6R63xRZbFD7fVFNNBcAUU0zRqCZ2JMOGDQNC3gwIc/0MM8zQlja1A6l5AA4//HAgqPqLjEdx+eWXA/Dvf/8bgJVXXjl7r1tys+g+D7DXXnsBQVGuPqN5Pl5/PvTQQ0BQ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8L8bmWiiier+TJz0OR+K+b3vNT0NbsvJ/z6bbLLJsuf5witaDyicfvTo0T3Os9BCCwEhCbRCxMoSZl+UeP445ZRTgFAg5b///S9QWRhJv19EPiQ1Xm9fffXVQEg2r3Go9WujQ7piuq8HG2OMMcYYY4wxxpg+J3IuJUpcBrD77rsDcMMNNwDFPAXa4dRu5qqrrtroJjaVWqXaa6mAGoG8CUcddVSv393sNrSCMWPGACGRs5DCwgT1AQTFxQsvvADAEkssAQQFXqxIOOmkk4Cg2ug0lJCyHq9k7OVWyfY33ngDCJ6RESNGALDWWmsVPq+86BCUHkpYf/311wOwww47FD5fO1GC72qlneUdl+dkoCFP3FVXXQVUv2dprOn+NsssswChlH01lER9oKkw6kEJP6VK0LiPVXYDFSUHjZM/yz4q764x25sKstvQ2kFqC7HooosCsPbaa7e8TWXgzDPPBODCCy9syPnkUc8nru8Gqil8xDzzzFPxqLXXQQcdlB0jFZDGZzesyWtRz1ys349HH310j/cWXHBBoLJEd6fT23pVSnMI5cKlwnvvvfeAoHSpttaV+mfvvfcGYLfddgPg3HPPbVjbm4kKX8SFZLQGF1Lm7LLLLr2eRwWhRHyfe/vttyveUz+95557AJhhhhmy96aeeuqiTS+ElT7GGGOMMcYYY4wxXUhXKX2++uqr7PmNN95Y+HPyims3c/nll29sw9pIM8ql1/qeakqfbkJqiTzbbrttaxtSYgYNGpQ9V36s/fbbDwgKKXk745wPiy++eIta2ByUN+z5558v/JkLLrggey6l06233grASiuNTZs288wz192WNddcs+7PlA2Vllc5yxjFWMuLVIu33noLgDnmmKOBrSsXUvzMO++8ALz22mvZe1IYqHx5rTwOUvbE/dJU54QTTgCCt1Nqz1aWai8bykmgUsnV2H///QGYeOKJW9KmsnDeeecBIe+W0H1P+SYHGvG6fXxI7So1LMCrr75accz2228PBEXZQEU53HT/Azj++OMBOOaYY4DuV/pMP/30QLEcf/fddx8AI0eO7PGelLTdxPDhw6u+/sEHH2TPNd56y90a556Rkli5F6UG0lpCaikotm5rFwceeCDQU90To7yIyqPVXx577LGKx1gNet111zXkO4SVPsYYY4wxxhhjjDFdSFcpfeLs2IonPP3006se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\n",
      "text/plain": [
       "<Figure size 1440x180 with 30 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "##########################\n",
    "### VISUALIZATION\n",
    "##########################\n",
    "\n",
    "\n",
    "train_loader = DataLoader(dataset=train_dataset, \n",
    "                          batch_size=15, \n",
    "                          shuffle=True)\n",
    "\n",
    "# Checking the dataset\n",
    "for images, labels in train_loader:  \n",
    "    print('Image batch dimensions:', images.shape)\n",
    "    print('Image label dimensions:', labels.shape)\n",
    "    break\n",
    "    \n",
    "# =============================================================\n",
    "\n",
    "n_images = 15\n",
    "image_width = 28\n",
    "\n",
    "fig, axes = plt.subplots(nrows=2, ncols=n_images, \n",
    "                         sharex=True, sharey=True, figsize=(20, 2.5))\n",
    "orig_images = features[:n_images]\n",
    "decoded_images = decoded[:n_images]\n",
    "\n",
    "for i in range(n_images):\n",
    "    for ax, img in zip(axes, [orig_images, decoded_images]):\n",
    "        curr_img = img[i].detach().to(torch.device('cpu'))\n",
    "        ax[i].imshow(curr_img.view((image_width, image_width)), cmap='binary')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Image batch dimensions: torch.Size([15, 1, 28, 28])\n",
      "Image label dimensions: torch.Size([15])\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABH0AAACqCAYAAAAwYjMwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nOyddaAkxfW2nw4JBBIcgsPimhBg4YcFAgSXxd1dwofDLu7uzmKBBPfFNVhCgF2cRRYITrAoEBIg/f2x+3bV9J0723PvSM/c9/ln5s709FSfW1VdU+c95yRpmmKMMcYYY4wxxhhjuovvtbsBxhhjjDHGGGOMMabxeNPHGGOMMcYYY4wxpgvxpo8xxhhjjDHGGGNMF+JNH2OMMcYYY4wxxpguxJs+xhhjjDHGGGOMMV2IN32MMcYYY4wxxhhjupB+bfokSbJakiSvJUnyRpIkQxvVKGOMMcYYY4wxxhjTP5I0Tfv2wSSZAHgdWBl4H3ga2CxN09GNa54xxhhjjDHGGGOM6Qv9UfosAbyRpulbaZr+F7gWGNKYZhljjDHGGGOMMcaY/vD9fnx2JuC96O/3gf+r9YFpppkmHTRoUD++sjMZNWrUZ2maTlvPZ2yr4thW9TEQ7fX222/z2WefJfV+biDaCjwO68G2Ko5tVRzP78Xx/F4fHofFsa2K4zmrOJ6z6sPjsDi1bNWfTZ9qnbVHrFiSJDsDOwPMOuusjBw5sh9f2ZkkSfJOweNsK9uqMEVtNe7YAW2vwYMHFz52oNsKPA7rwbYqjm1VHM/vxfH8Xh8eh8WxrYrjOas4nrPqw+OwOLVs1Z/wrveBWaK/ZwY+zB+UpunwNE0Hp2k6eNpp694AHlDYVsWxrerD9iqObVUc26o4tlVxbKv6sL2KY1sVx7Yqjm1VH7ZXcWyr4thWtenPps/TwNxJksyeJMmEwKbAiMY0yxhjjDHGGGOMMcb0hz6Hd6Vp+m2SJL8G7gUmAC5L0/TlhrXMGGOMMcYYY4wxxvSZ/uT0IU3Tu4C7GtQWY4wxxhhjjDHGGNMg+hPeZYwxxhhjjDHGGGNKSr+UPsYYY4wx3cQrr7wCwFVXXQXA8ccfD8D//ve/trXJGGOMMaavWOljjDHGGGOMMcYY04VY6WOMMcaYAcXw4cMBuOWWW7LXPvvsMwBeffVVAL788ksAkiQBYN99982OPfjggwGYZpppmt9Y0/W89tpr2fPll18egCOPPBKAXXfdtR1NMiXl22+/zZ5fcsklABx99NEA/OUvfwEgTVMA1l577exYKRYXWmihlrSzzHz++ecAHHbYYQC89NJLAGy//fbZMeuvvz4Ak002WYtbVy7OPvtsINwHL7roIgBGjx6dHXPmmWdWHDP55JMDsPXWW7esnWb8WOljjDHGGGOMMcYY04V0pNLn9NNPB+CYY44B4B//+Eevx2q3++c//zlQe9dxn332aVQT24q8QwCPPPIIAA8//PB4P/fLX/4SCF4m/a1H0zvffPMNELy/AKeeeioAG2+8MQDXXXdd6xtWcmJPgTwtstvTTz8NwG677QbA+eef3+LWNZ6///3vANxwww0A/Pa3v83ek8pgvvnmA4J3d5VVVmllE43pGj799NPs+S677ALArbfeCoS1gTyT1V7T3+KMM87InsuzqXvrcsst18immwGCVBvx/e3jjz8GYNlll21Lm8rCv/71LyAo7o466igALrzwwl4/I6XGGmusAcAGG2zQzCa2hfXWWy97ftddlQWUZ5ppJgA++OADAO68887svRdeeAEIa6qDDjqoqe0sI8rXttZaawHw1ltvVbz/2GOPZc+feOIJIChbuhn9VnznnXey14477jgAxowZA1TeK/N/77333hWvTTjhhBV/b7XVVs1otqkTK32MMcYYY4wxxhhjupCOVPrsv//+QNhBzO8+VkM73PpsNeTFU6z/aqut1q92tgp5GldYYYWGnEeP8qrESp8jjjiix2smeOlOO+207DX1S8UMm6BmOemkkwA477zzsve+/vprAKaffnoAppxySgBuuummis8ATDrppM1vbAORx/aLL74AwnwUM8ssswBBiaBxeNZZZwHws5/9bLzf86Mf/QiAueaaq38NbiPyQtbjXaum2sijfnXiiScC3RVr/p///AcIXrpRo0Zl78lbeeONNwLw0Ucf9fl7Zp555uz5KaecAsCmm27a5/M1Cyl85O2HYJNa3sreXqt1zH777QfA3XffDXRvjh/NzxqfEKqb6R63xRZbFD7fVFNNBcAUU0zRqCZ2JMOGDQNC3gwIc/0MM8zQlja1A6l5AA4//HAgqPqLjEdx+eWXA/Dvf/8bgJVXXjl7r1tys+g+D7DXXnsBQVGuPqN5Pl5/PvTQQ0BQ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8L8bmWiiier+TJz0OR+K+b3vNT0NbsvJ/z6bbLLJsuf5witaDyicfvTo0T3Os9BCCwEhCbRCxMoSZl+UeP445ZRTgFAg5b///S9QWRhJv19EPiQ1Xm9fffXVQEg2r3Go9WujQ7piuq8HG2OMMcYYY4wxxpg+J3IuJUpcBrD77rsDcMMNNwDFPAXa4dRu5qqrrtroJjaVWqXaa6mAGoG8CUcddVSv393sNrSCMWPGACGRs5DCwgT1AQTFxQsvvADAEkssAQQFXqxIOOmkk4Cg2ug0lJCyHq9k7OVWyfY33ngDCJ6RESNGALDWWmsVPq+86BCUHkpYf/311wOwww47FD5fO1GC72qlneUdl+dkoCFP3FVXXQVUv2dprOn+NsssswChlH01lER9oKkw6kEJP6VK0LiPVXYDFSUHjZM/yz4q764x25sKstvQ2kFqC7HooosCsPbaa7e8TWXgzDPPBODCCy9syPnkUc8nru8Gqil8xDzzzFPxqLXXQQcdlB0jFZDGZzesyWtRz1ys349HH310j/cWXHBBoLJEd6fT23pVSnMI5cKlwnvvvfeAoHSpttaV+mfvvfcGYLfddgPg3HPPbVjbm4kKX8SFZLQGF1Lm7LLLLr2eRwWhRHyfe/vttyveUz+95557AJhhhhmy96aeeuqiTS+ElT7GGGOMMcYYY4wxXUhXKX2++uqr7PmNN95Y+HPyims3c/nll29sw9pIM8ql1/qeakqfbkJqiTzbbrttaxtSYgYNGpQ9V36s/fbbDwgKKXk745wPiy++eIta2ByUN+z5558v/JkLLrggey6l06233grASiuNTZs288wz192WNddcs+7PlA2Vllc5yxjFWMuLVIu33noLgDnmmKOBrSsXUvzMO++8ALz22mvZe1IYqHx5rTwOUvbE/dJU54QTTgCCt1Nqz1aWai8bykmgUsnV2H///QGYeOKJW9KmsnDeeecBIe+W0H1P+SYHGvG6fXxI7So1LMCrr75accz2228PBEXZQEU53HT/Azj++OMBOOaYY4DuV/pMP/30QLEcf/fddx8AI0eO7PGelLTdxPDhw6u+/sEHH2TPNd56y90a556Rkli5F6UG0lpCaikotm5rFwceeCDQU90To7yIyqPVXx577LGKx1gNet111zXkO4SVPsYYY4wxxhhjjDFdSFcpfeLs2IonPP3006se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\n",
      "text/plain": [
       "<Figure size 1440x180 with 30 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "test_loader = DataLoader(dataset=test_dataset, \n",
    "                         batch_size=15, \n",
    "                         shuffle=True)\n",
    "\n",
    "# Checking the dataset\n",
    "for images, labels in test_loader:  \n",
    "    print('Image batch dimensions:', images.shape)\n",
    "    print('Image label dimensions:', labels.shape)\n",
    "    break\n",
    "    \n",
    "# =============================================================\n",
    "\n",
    "n_images = 15\n",
    "image_width = 28\n",
    "\n",
    "fig, axes = plt.subplots(nrows=2, ncols=n_images, \n",
    "                         sharex=True, sharey=True, figsize=(20, 2.5))\n",
    "orig_images = features[:n_images]\n",
    "decoded_images = decoded[:n_images]\n",
    "\n",
    "for i in range(n_images):\n",
    "    for ax, img in zip(axes, [orig_images, decoded_images]):\n",
    "        curr_img = img[i].detach().to(torch.device('cpu'))\n",
    "        ax[i].imshow(curr_img.view((image_width, image_width)), cmap='binary')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Scikit-learn Classifier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### On Original MNIST"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "\n",
    "\n",
    "train_loader = DataLoader(dataset=train_dataset, \n",
    "                          batch_size=60000, \n",
    "                          shuffle=True)\n",
    "\n",
    "test_loader = DataLoader(dataset=test_dataset, \n",
    "                          batch_size=10000, \n",
    "                          shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Image batch dimensions: torch.Size([60000, 1, 28, 28])\n",
      "Image label dimensions: torch.Size([60000])\n",
      "Image batch dimensions: torch.Size([10000, 1, 28, 28])\n",
      "Image label dimensions: torch.Size([10000])\n"
     ]
    }
   ],
   "source": [
    "for images, labels in train_loader:  \n",
    "    print('Image batch dimensions:', images.shape)\n",
    "    print('Image label dimensions:', labels.shape)\n",
    "    break\n",
    "\n",
    "X_train = np.array(images.reshape(60000, 28*28))\n",
    "y_train = np.array(labels)\n",
    "\n",
    "\n",
    "for images, labels in test_loader:  \n",
    "    print('Image batch dimensions:', images.shape)\n",
    "    print('Image label dimensions:', labels.shape)\n",
    "    break\n",
    "\n",
    "X_test = np.array(images.reshape(10000, 28*28))\n",
    "y_test = np.array(labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train Accuracy: 100.0%\n",
      "Test Accuracy: 97.09%\n"
     ]
    }
   ],
   "source": [
    "rf = RandomForestClassifier(n_estimators=500, n_jobs=-1).fit(X_train, y_train)\n",
    "print(f'Train Accuracy: {rf.score(X_train, y_train)*100}%')\n",
    "print(f'Test Accuracy: {rf.score(X_test, y_test)*100}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Using PCA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.decomposition import PCA\n",
    "\n",
    "pca = PCA(n_components=32)  # same size as autoencoder latent space\n",
    "X_train_pca = pca.fit_transform(X_train)\n",
    "X_test_pca = pca.transform(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train Accuracy: 100.0%\n",
      "Test Accuracy: 95.7%\n"
     ]
    }
   ],
   "source": [
    "rf = RandomForestClassifier(n_estimators=500, n_jobs=-1).fit(X_train_pca, y_train)\n",
    "print(f'Train Accuracy: {rf.score(X_train_pca, y_train)*100}%')\n",
    "print(f'Test Accuracy: {rf.score(X_test_pca, y_test)*100}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Compressed MNIST"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loader = DataLoader(dataset=train_dataset, \n",
    "                          batch_size=1000, \n",
    "                          shuffle=True)\n",
    "\n",
    "test_loader = DataLoader(dataset=test_dataset, \n",
    "                          batch_size=1000, \n",
    "                          shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train_compr = np.ones((60000, num_hidden_1))\n",
    "y_train = np.ones(60000)\n",
    "\n",
    "start_idx = 0\n",
    "\n",
    "for idx, (images, labels) in enumerate(train_loader): \n",
    "    features = images.view(-1, 28*28).to(device)\n",
    "    decoded = model.encoder(features)\n",
    "    X_train_compr[start_idx:start_idx+1000] = decoded.to(torch.device('cpu')).detach().numpy()\n",
    "    y_train[start_idx:start_idx+1000] = labels\n",
    "    start_idx += 1000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_test_compr = np.ones((10000, num_hidden_1))\n",
    "y_test = np.ones(10000)\n",
    "\n",
    "start_idx = 0\n",
    "\n",
    "for idx, (images, labels) in enumerate(test_loader): \n",
    "    features = images.view(-1, 28*28).to(device)\n",
    "    decoded = model.encoder(features)\n",
    "    X_test_compr[start_idx:start_idx+1000] = decoded.to(torch.device('cpu')).detach().numpy()\n",
    "    y_test[start_idx:start_idx+1000] = labels\n",
    "    start_idx += 1000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train Accuracy: 100.0%\n",
      "Test Accuracy: 95.23%\n"
     ]
    }
   ],
   "source": [
    "rf = RandomForestClassifier(n_estimators=500, n_jobs=-1).fit(X_train_compr, y_train)\n",
    "print(f'Train Accuracy: {rf.score(X_train_compr, y_train)*100}%')\n",
    "print(f'Test Accuracy: {rf.score(X_test_compr, y_test)*100}%')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch       1.3.0\n",
      "torchvision 0.4.1a0+d94043a\n",
      "numpy       1.17.2\n",
      "matplotlib  3.1.0\n",
      "\n"
     ]
    }
   ],
   "source": [
    "%watermark -iv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
